﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SoftwareConsulting.BI11.Studio.Core.Project;
using SoftwareConsulting.BI11.Studio.Core.Project.SituationsHierarchy;
using SoftwareConsulting.BI11.Studio.Core.Project.BIML;
using SoftwareConsulting.BI11.Studio.Core.Project.Metadata;
using SoftwareConsulting.BI11.Studio.UI.ProjectExplorer;
using SoftwareConsulting.Interfaces.BasicEntities;
using System.IO;
using SoftwareConsulting.BI11.Studio.InternalServices;
using SoftwareConsulting.BI11.Studio.UI.Properties;

namespace SoftwareConsulting.BI11.Studio.UI.IDE
{
    /// <summary>
    /// Класс формы среды разработки
    /// </summary>
    public partial class IDEForm : RestorableForm
    {
        private ProjectExplorerForm _projectExplorerLink; //для связи с формой обозревателя проекта
        private ErrorInfoCollection _errors; //ошибки компиляции        

        /// <summary>
        /// Возвращает/устанавливает список ошибок компиляции
        /// </summary>
        public ErrorInfoCollection Errors
        {
            get
            {
                return _errors;
            }
            set
            {
                _errors = value;
            }
        }

        public IDEForm(ProjectExplorerForm projectExplorerLink)
        {
            _projectExplorerLink = projectExplorerLink;            
            InitializeComponent();
        }

        public ProjectDescriptor ProjectLink
        {
            get
            {
                return _projectExplorerLink.ProjectLink;
            }
        }

        /// <summary>
        /// Возвращает ссылку на форму обозревателя проекта
        /// </summary>
        public ProjectExplorerForm ProjectExplorerLink
        {
            get
            {
                return _projectExplorerLink;
            }
        }

        /// <summary>
        /// Выполняет необходимые действия перед закрытием окна среды разработки
        /// </summary>
        private void BeforeClose()
        {            
            ProjectExplorerLink.IDEWindow = null;
        }

        /// <summary>
        /// Добавляет окно свода действий или активирует имеющееся
        /// </summary>
        public ActionSetForm AddActionSetWindow(IActionSet actionSet)
        {
            ActionSetForm same = null;
            foreach (Form f in MdiChildren)
            {
                ActionSetForm actsetform = f as ActionSetForm;
                if (actsetform.ActionSet.Id == actionSet.Id)
                {
                    same = actsetform;
                    break;
                }
            }
            if (same == null)
            {
                same = new ActionSetForm(this, actionSet);
                same.MdiParent = this;
                same.Show();
            }
            else
            {
                same.Focus();
            }
            return same;
        }

        /// <summary>
        /// Обновляет заголовок окна свода действий, если он открыт
        /// </summary>
        public void UpdateActionSetWindowCaption(IActionSet actionSet)
        {            
            foreach (Form f in MdiChildren)
            {
                ActionSetForm actsetform = f as ActionSetForm;
                if (actsetform.ActionSet.Id == actionSet.Id)
                {
                    actsetform.UpdateCaptionName();
                    break;
                }
            }                        
        }

        /// <summary>
        /// Закрывает окно свода действий, если оно открыто
        /// </summary>
        public bool CloseActionSetWindow(IActionSet actionSet)
        {            
            foreach (Form f in MdiChildren)
            {
                ActionSetForm actsetform = f as ActionSetForm;
                if (actsetform.ActionSet.Id == actionSet.Id)
                {                    
                    actsetform.Close();
                    if (actsetform.IsDisposed)
                        return true;
                    else
                        return false;
                }
            }
            return true;
        }        

        /// <summary>
        /// Сохраняет текущий свод действий
        /// </summary>
        private void SaveCurrent()
        {
            (ActiveMdiChild as ActionSetForm).Save();
            //UpdateAbilities(null);
        }

        /// <summary>
        /// Создает новый свод действий
        /// </summary>
        /// <returns></returns>
        private ActionSetForm CreateActionSet()
        {
            ActionSetForm actsetform = null;
            CreateObjectDialog newObjectDialog = new CreateObjectDialog(ProjectExplorerLink, MetadataObjectKind.ActionSet, ProjectLink.RepositoryLink.RootFolder.Descriptor); /*TODO: пока пусть всегда в корне создается, потом доработаю*/
            if (newObjectDialog.ShowDialog() == DialogResult.OK)
            {
                IActionSet actset = newObjectDialog.CreatedObject as IActionSet;
                actsetform = AddActionSetWindow(actset);
            }
            return actsetform;
        }

        /// <summary>
        /// Отображает диалог открытия модуля из файла
        /// </summary>
        private void OpenFromFile()
        {
            ActionSetForm actsetform = CreateActionSet();
            if (actsetform != null)
            {
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    StreamReader reader = File.OpenText(openFileDialog1.FileName);
                    List<string> lines = new List<string>();
                    while (!reader.EndOfStream)
                    {
                        lines.Add(reader.ReadLine());
                    }
                    reader.Close();
                    reader.Dispose();
                    reader = null;
                    actsetform.Code = lines;                    
                    actsetform.Save();
                }
            }
        }

        /// <summary>
        /// Добавляет строку с ошибкой
        /// </summary>
        /// <param name="text"></param>
        /// <param name="kind"></param>
        /// <param name="row"></param>
        /// <param name="column"></param>
        private void AddError(string text, ErrorKind kind, int row, int column)
        {
            ListViewItem lvi = ErrorsBox.Items.Add(string.Empty);
            //lvi.BackColor = kind == ErrorKind.Error ? Color.Red : (kind == ErrorKind.Warning ? Color.Yellow : SystemColors.Window); ;            
            //lvi.ImageKey = kind == ErrorKind.Error ? "error" : (kind == ErrorKind.Warning ? "warning" : (kind == ErrorKind.Information ? "information" : "ok"));
            lvi.StateImageIndex = kind == ErrorKind.Error ? imageList1.Images.IndexOfKey("error") :
                (kind == ErrorKind.Warning ? imageList1.Images.IndexOfKey("warning") :
                (kind == ErrorKind.Information ? imageList1.Images.IndexOfKey("information") :
                imageList1.Images.IndexOfKey("ok")));
            lvi.SubItems.Add(text);
            if (row != -1)
                lvi.SubItems.Add((row + 1).ToString(CultureInfo.CurrentCulture));
            else
                lvi.SubItems.Add(string.Empty);
            if (column != -1)
                lvi.SubItems.Add((column + 1).ToString(CultureInfo.CurrentCulture));
            else
                lvi.SubItems.Add(string.Empty);
            if (kind == ErrorKind.Error)
            {
                (ActiveMdiChild as ActionSetForm).PutCursor(row, column);
            }
        }

        /// <summary>
        /// Отображает ошибки компилятора
        /// </summary>        
        public void ShowErrors()
        {
            ErrorsBox.Items.Clear();            
            if (!ErrorsBox.Visible)
                ShowCompilerMessagesPanel();            
            if (_errors.ItemsCount == 0)
            {
                //ошибок нет
                AddError(Resources.BI_BIML_NOERRORS, ErrorKind.None, -1, -1);
                return;
            }
            foreach (ErrorInfo erinfo in _errors)
            {                
                AddError(erinfo.ToString(), erinfo.Kind, erinfo.Row, erinfo.Column);
            }            
        }

        /// <summary>
        /// Обновляет название окна
        /// </summary>
        public void UpdateCaptionName()
        {
            Text = string.Format(Resources.BI_FRAMECHILD_MASK, Resources.BI_IDEWINDOW_CAPTION, _projectExplorerLink.ProjectLink.Name);            
        }

        /// <summary>
        /// Отображает панель сообщений компилятора
        /// </summary>
        private void ShowCompilerMessagesPanel()
        {
            сообщенияКомпилятораToolStripMenuItem.Checked = !сообщенияКомпилятораToolStripMenuItem.Checked;
            if (сообщенияКомпилятораToolStripMenuItem.Checked)
            {
                ErrorsBox.Show();
            }
            else
            {
                ErrorsBox.Hide();
            }
        }

        /// <summary>
        /// Обновляет доступные возможности
        /// </summary>
        public void UpdateAbilities(ActionSetForm formToIgnore)
        {
            int minimum = formToIgnore == null ? 0 : 1;
            CompileButton.Enabled = MdiChildren.Length > minimum;
            bool haveUnsaved = false;
            foreach (Form f in MdiChildren)
            {
                ActionSetForm actsetform = f as ActionSetForm;
                haveUnsaved = actsetform.ActionSet.Modified && !actsetform.Equals(formToIgnore);
                if (haveUnsaved)
                    break;
            }
            SaveButton.Enabled = haveUnsaved;
            сохранитьToolStripMenuItem.Enabled = haveUnsaved;
        }

        /// <summary>
        /// Компилирует текущий модуль
        /// </summary>
        private void CompileCurrent()
        {
            (ActiveMdiChild as ActionSetForm).Compile();
        }

        /// <summary>
        /// Инициализация формы
        /// </summary>
        private void Initialize()
        {
            //_blockErrSelProcess = false;
            UpdateCaptionName();
            ErrorsBox.Hide();
            WindowState = FormWindowState.Maximized;        
        }

        /// <summary>
        /// Выбор объекта "свод действий" из обозревателя проекта
        /// </summary>
        private void OpenFromProjectExplorer()
        {
            //_MainFormLink.ShowMetadataExplorerForm(MetadataObjectKind.ActionSet);
            SelectObjectDialog sod = new SelectObjectDialog(_projectExplorerLink, MetadataObjectKind.ActionSet, true);
            if (sod.ShowDialog() == DialogResult.OK)
            {
                ICollection<Guid> ids = sod.SelectedObjectIds;
                foreach (Guid id in ids)
                {
                    IActionSet actset = ProjectLink.RepositoryLink.GetObjectDescriptorById(id) as IActionSet;
                    AddActionSetWindow(actset);
                }
            }
        }

        /// <summary>
        /// Отображает или скрывает окно используемых сводов
        /// </summary>
        /// <param name="toShow"></param>
        private void ShowOrHideLinksWindow(bool toShow)
        {
            if (toShow)
            {
                UsedWindow.Show();
            }
            else
            {
                UsedWindow.Hide();
            }
        }

        /// <summary>
        /// Обновляет список используемых сводов действий
        /// </summary>
        public void RefreshUsed()
        {
            INamedHierarchy<IActionSet> actsets = (ActiveMdiChild as ActionSetForm).ActionSet.UsedActionSets;
            actsets.Sort();
            UsedWindow.Items.Clear();
            foreach(IActionSet actset in actsets)
            {                                
                ListViewItem item = UsedWindow.Items.Add(actset.Name);
                item.SubItems.Add(actset.Label);
                item.Tag = actset.Descriptor;
            }
        }

        /// <summary>
        /// Удаляет выделенные своды действий из списка используемых
        /// </summary>
        private void DeleteSelectedUsed()
        {
            IActionSet actset = (ActiveMdiChild as ActionSetForm).ActionSet;
            foreach (ListViewItem item in UsedWindow.SelectedItems)
            {
                actset.DeleteUsedActionSet((item.Tag as MetadataObjectDescriptor).Bind() as IActionSet);
            }
            RefreshUsed();
        }

        /// <summary>
        /// Вызывает диалог добавления используемых сводов действий
        /// </summary>
        private void AddUsed()
        {            
            SelectObjectDialog sod = new SelectObjectDialog(_projectExplorerLink, MetadataObjectKind.ActionSet, true);
            if (sod.ShowDialog() == DialogResult.OK)
            {
                IActionSet actset = (ActiveMdiChild as ActionSetForm).ActionSet;
                ICollection<Guid> ids = sod.SelectedObjectIds;
                foreach (Guid id in ids)
                {
                    try
                    {
                        actset.AddUsedActionSet(ProjectLink.RepositoryLink.GetObjectDescriptorById(id).Bind() as IActionSet);
                    }
                    catch (BIActionSetCyclesException ex)
                    {
                        GeneralMethods.ShowUserError(ex.Message);
                    }
                    catch (BIActionSetSameUsedException ex)
                    {
                        GeneralMethods.ShowUserError(ex.Message);
                    }
                }
                RefreshUsed();
            }            
        }

        /// <summary>
        /// Обрабатывает даблклик по ошибке
        /// </summary>
        private void ProcessErrorDoubleClick()
        {
            if (ErrorsBox.SelectedItems.Count > 0)
            {
                string rowstr = ErrorsBox.SelectedItems[0].SubItems[2].Text;
                string colstr = ErrorsBox.SelectedItems[0].SubItems[3].Text;
                if (!string.IsNullOrEmpty(rowstr) && !string.IsNullOrEmpty(colstr))
                {
                    int row;
                    int col;
                    row = int.Parse(rowstr, CultureInfo.CurrentCulture) - 1;
                    col = int.Parse(colstr, CultureInfo.CurrentCulture) - 1;
                    (ActiveMdiChild as ActionSetForm).Focus();
                    (ActiveMdiChild as ActionSetForm).PutCursor(row, col);                    
                }
            }
        }

        private void IDEForm_Load(object sender, EventArgs e)
        {
            Initialize();
        }

        private void IDEForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            BeforeClose();
        }

        private void закрытьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void перейтиКИерархииСитуацийToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ProjectExplorerLink.Focus();
        }

        private void оПрограммеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ProjectExplorerLink.ShowAboutDialog();
        }

        private void открытьИзФайлаToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFromFile();
        }


        private void CompileButton_Click(object sender, EventArgs e)
        {
            CompileCurrent();
        }

        private void ErrorsBox_DoubleClick(object sender, EventArgs e)
        {
            ProcessErrorDoubleClick();
        }

        private void ErrorsBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            /*if (!_blockErrSelProcess)
            {
                int index = ErrorsBox.SelectedItems.Count > 0 ? ErrorsBox.SelectedItems[0].Index : -1;
                ShowErrors();
                if (index != -1)
                {
                    _blockErrSelProcess = true;
                    ErrorsBox.Items[index].Selected = true;
                    _blockErrSelProcess = false;
                }
            }*/
        }

        private void сохранитьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveCurrent();
        }

        private void SaveButton_Click(object sender, EventArgs e)
        {
            SaveCurrent();
        }

        private void создатьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CreateActionSet();
        }

        private void NewButton_Click(object sender, EventArgs e)
        {
            CreateActionSet();
        }

        private void выбратьИзОбозревателяМетаданныхToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFromProjectExplorer();
        }

        private void используемыеСводыДействийToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowOrHideLinksWindow(используемыеСводыДействийToolStripMenuItem.Checked);
        }

        private void сообщенияКомпилятораToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowCompilerMessagesPanel();
        }

        private void DeleteUsedButton_Click(object sender, EventArgs e)
        {
            DeleteSelectedUsed();
        }

        private void AddUsedButton_Click(object sender, EventArgs e)
        {
            AddUsed();
        }
    }
}
